/**
 * author: volcaner
 * create: 04/28/2020
 */


/** _toString
 * Get the raw type string of a value, e.g., [object Object].
 */
 const _toString = Object.prototype.toString;



 /** _getDeepParamVal
  * [_getDeepParamVal 传递 paramKeys 数组，在 obj 对象中查找到对应的值]
  * paramKeys: 为 obj 的参数层级
  * [
  *  如：
  *    obj = {
  *      aaa: {
  *        bbb: '我是值'
  *      }
  *    }
  *
  *    paramsKey = [ 'aaa', 'bbb' ]
  *
  *    return obj['aaa']['bbb']
  * ]
  * @使用场景: cardLists
  * @return: val / undefined
  */
 export const _getDeepParamVal = (obj, paramKeys) => {
   // console.log('_getDeepParamVal: ');
   // let val = obj;
   // val = paramKeys.length <=  0 ? val :
   //   this._getDeepParamVal( obj[ paramKeys.shift() ],  paramKeys );
 
   let val;
   try {
     if( !( isObject(obj) || isArray(obj) )
       && ( !isArray(paramKeys) || paramKeys.length <= 0 ) ) throw new Error('EndIterative');
 
     const key = paramKeys.shift();
     if( !isHasOwnProperty(obj, key) ) throw new Error('EndIterative');
 
     if( paramKeys.length <= 0 ) val = _.cloneDeep(obj[key]);
     else val = _getDeepParamVal(obj[key], paramKeys);
   } catch(e) {
     // 不存在 key,结束迭代
     console.log('Error: ', e.message);
     val = e;
   }
 
   return val;
 };
 
 /** _getDataType
  * [_getDataType description]
  * @param  {[type]} val [description]
  * @return {[type]}     [description]
  */
 export const _getDataType = (val) => {
   return _toString.call(val);
 };
 
 /** isNumber
  * [isNumber description]
  * @param  {[type]}  val [description]
  * @return {Boolean}     [description]
  */
 export const isNumber = (val) => {
   return _toString.call(val) === "[object Number]";
 };
 
 /** isObject
  * [isObject description]
  * @param  {[type]}  val [description]
  * @return {Boolean}     [description]
  */
 export const isObject = (val) => {
   return _toString.call(val) === "[object Object]";
 };
 
 /** isFunction
  * [isFunction description]
  * @param  {[type]}  val [description]
  * @return {Boolean}     [description]
  */
 export const isFunction = (val) => {
   return _toString.call(val) === "[object Function]";
 };
 
 /** isArray
  * [isArray description]
  * @param  {[type]}  val [description]
  * @return {Boolean}     [description]
  */
 export const isArray = (val) => {
   return _toString.call(val) === "[object Array]";
 };
 
 /** isString
  * [isString description]
  * @param  {[type]}  val [description]
  * @return {Boolean}     [description]
  */
 export const isString = (val) => {
   return _toString.call(val) === "[object String]";
 };
 
 /** isUndefined
  * [isUndefined description]
  * @param  {[type]}  val [description]
  * @return {Boolean}     [description]
  */
 export const isUndefined = (val) => {
   return _toString.call(val) === "[object Undefined]";
 };
 
 /** isAbsUndef
  * typeof 较安全:
  *  1. 未申明(Uncaught ReferenceError: is not defined)
  *  2. undefined
  *  3. null
  * @param  {[type]}  val [description]
  * @return {Boolean}     [description]
  */
 export const isAbsUndef = (val) => {
   return typeof val === 'undefined' || val === null;
 };
 
 /** isHasOwnProperty
  * [isHasOwnProperty description]
  * @param  {[type]}  obj [description]
  * @param  {[type]}  key [description]
  * @return {Boolean}     [description]
  */
 export const isHasOwnProperty = (obj, key) => {
   return !isAbsUndef(obj) && Object.prototype.hasOwnProperty.call(obj, key);
 };
 
 /** isArrayEquals
  * [isArrayEquals description]
  * @param  {[type]}  arr1 [description]
  * @param  {[type]}  arr2 [description]
  * @return {Boolean}      [description]
  */
 export const isArrayEquals = (arr1, arr2) => {
   if(!(arr1 || arr2)) return false;
 
   if(arr1.length != arr2.length) return false;
 
   for(let i = 0, l = arr1.length; i < l; i++) {
     if(arr1[i] instanceof Array && arr2[i] instanceof Array) {
       if(!isArrayEquals(arr1[i], arr2[i])) return false;
     }
     else if(arr1[i] instanceof Object && arr2[i] instanceof Object) {
       if(!isObjectEquals(arr1[i], arr2[i])) return false;
     }
     else if(arr1[i] != arr2[i]) {
       return false
     };
   }
 
   return true;
 };
 
 /** isObjectEquals
  * [isObjectEquals description]
  * @param  {[type]}  object1 [description]
  * @param  {[type]}  object1 [description]
  * @return {Boolean}         [description]
  */
 export const isObjectEquals = (object1, object2) => {
   const keys1 = Object.keys(object1);
   const keys2 = Object.keys(object2);
 
   if (keys1.length !== keys2.length) return false;
 
   for (let index = 0; index < keys1.length; index++) {
     const val1 = object1[keys1[index]];
     const val2 = object2[keys2[index]];
     const areObjects = isObject(val1) && isObject(val2);
     if (areObjects && !isObjectEquals(val1, val2) || !areObjects && val1 !== val2) return false;
   }
 
   return true;
 };
 
 /** WindowClient
  * [WindowClient description]
  */
 export const _getWindowClient = () => {
   if(window.innerWidth != null) {  // ie9 +  最新浏览器
     return {
       width: window.innerWidth,
       height: window.innerHeight
     }
   }
   else if(document.compatMode === "CSS1Compat") {  // 标准浏览器
     return {
       width: document.documentElement.clientWidth,
       height: document.documentElement.clientHeight
     }
   }
   return {   // 怪异浏览器
     width: document.body.clientWidth,
     height: document.body.clientHeight
   }
 };
 
 /** _cloneDeep
  * [_cloneDeep 深拷贝]
  * @param  {[type]} val [description]
  * @return {[type]}     [description]
  */
 export const _cloneDeep = (val) => {
   if (isAbsUndef(val) || (!isArray(val) && !isObject(val))) return val;
   let _newVal;
   const _isArr = isArray(val);
   if (_isArr) {
     _newVal = [];
     let i = val.length;
     while (i--) {
       _newVal.unshift(_cloneDeep(val[i]));
     }
   } else {
     _newVal = {};
     let _keys = Object.keys(val);
     let j = _keys.length;
     while (j--) {
       _newVal[_keys[j]] = _cloneDeep(val[_keys[j]]);
     }
   }
 
   return _newVal;
 };
 